home *** CD-ROM | disk | FTP | other *** search
/ Network PC / Network PC.iso / amiga utilities / communication / bbs / termv4.6 / extras / source / term-source.lha / Locale.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-18  |  16.0 KB  |  861 lines

  1. /*
  2. **    Locale.c
  3. **
  4. **    Localization support routines
  5. **
  6. **    Copyright © 1990-1996 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. **
  9. **    :ts=4
  10. */
  11.  
  12. #ifndef _GLOBAL_H
  13. #include "Global.h"
  14. #endif
  15.  
  16.     /* The catalog data is stored in the following format. */
  17.  
  18. struct CatCompArrayType
  19. {
  20.     ULONG    cca_ID;
  21.     STRPTR    cca_Str;
  22. };
  23.  
  24.     /* LocaleOpen(STRPTR CatalogName,STRPTR BuiltIn):
  25.      *
  26.      *    Open string translation tables.
  27.      */
  28.  
  29. VOID
  30. LocaleOpen(STRPTR CatalogName,STRPTR BuiltIn,LONG Version)
  31. {
  32.     DecimalPoint = '.';
  33.  
  34.     if(LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",38))
  35.     {
  36.         if(LocaleBase->lb_SysPatches)
  37.         {
  38.             strcpy(ConvNumber,"%lD");
  39.             strcpy(ConvNumber10,"%10lD");
  40.  
  41.             if(Catalog = OpenCatalog(NULL,CatalogName,
  42.                 OC_BuiltInLanguage,    BuiltIn,
  43.                 OC_BuiltInCodeSet,    0,
  44.  
  45.                 Language[0] ? OC_Language : TAG_IGNORE,Language,
  46.             TAG_DONE))
  47.             {
  48.                 BOOL TooOld = FALSE;
  49.  
  50.                     // Don't load an outdated catalog file
  51.  
  52.                 if(Catalog->cat_Version < Version)
  53.                     TooOld = TRUE;
  54.                 else
  55.                 {
  56.                     if(strcmp(GetCatalogStr(Catalog,MSG_OFFSET_TEST1_TXT,""),"v4.0"))
  57.                         TooOld = TRUE;
  58.                 }
  59.  
  60.                 if(TooOld)
  61.                 {
  62.                     struct IntuitionBase *IntuitionBase;
  63.  
  64.                     if(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0))
  65.                     {
  66.                         ShowRequest(NULL,"The catalog file is too old to be used\nwith this `term' revision.","Continue");
  67.  
  68.                         CloseLibrary(IntuitionBase);
  69.                     }
  70.  
  71.                     CloseCatalog(Catalog);
  72.                     Catalog = NULL;
  73.                 }
  74.             }
  75.  
  76.             Locale = OpenLocale(NULL);
  77.  
  78.             DecimalPoint = Locale->loc_DecimalPoint[0];
  79.         }
  80.         else
  81.         {
  82.             strcpy(ConvNumber,"%ld");
  83.             strcpy(ConvNumber10,"%10ld");
  84.  
  85.             CloseLibrary(LocaleBase);
  86.             LocaleBase = NULL;
  87.         }
  88.     }
  89.     else
  90.     {
  91.         strcpy(ConvNumber,"%ld");
  92.         strcpy(ConvNumber10,"%10ld");
  93.     }
  94. }
  95.  
  96.     /* LocaleClose():
  97.      *
  98.      *    Close the translation tables.
  99.      */
  100.  
  101. VOID
  102. LocaleClose()
  103. {
  104.     if(LocaleBase)
  105.     {
  106.         CloseLocale(Locale);
  107.         Locale = NULL;
  108.  
  109.         CloseCatalog(Catalog);
  110.         Catalog = NULL;
  111.  
  112.         CloseLibrary(LocaleBase);
  113.         LocaleBase = NULL;
  114.     }
  115. }
  116.  
  117.     /* LanguageCheck():
  118.      *
  119.      *    Checks to see if the currently selected language
  120.      *    is english.
  121.      */
  122.  
  123. VOID
  124. LanguageCheck()
  125. {
  126.     if(Locale && Catalog)
  127.     {
  128.         if(Locale->loc_LanguageName)
  129.         {
  130.             if(!Stricmp(Locale->loc_LanguageName,"english.language"))
  131.                 English = TRUE;
  132.             else
  133.                 English = FALSE;
  134.         }
  135.         else
  136.             English = FALSE;
  137.     }
  138.     else
  139.         English = TRUE;
  140. }
  141.  
  142.     /* LocaleSeconds(LONG Seconds):
  143.      *
  144.      *    Return seconds in proper format.
  145.      */
  146.  
  147. STRPTR
  148. LocaleSeconds(LONG Seconds)
  149. {
  150.     STATIC UBYTE Time[10];
  151.  
  152.     if(Locale)
  153.         SPrintf(Time,"%2lD%s%02lD",Seconds / 100,Locale->loc_DecimalPoint,Seconds % 100);
  154.     else
  155.         SPrintf(Time,"%2ld.%02ld",Seconds / 100,Seconds % 100);
  156.  
  157.     return(Time);
  158. }
  159.  
  160.     /* SmallCurrency():
  161.      *
  162.      *    Support function for the rates control panel, returns a formatted
  163.      *    string to contain a string like "cents/unit".
  164.      */
  165.  
  166. STRPTR
  167. SmallCurrency()
  168. {
  169.     STATIC UBYTE Buffer[30];
  170.  
  171.     if(Locale)
  172.         SPrintf(Buffer,LocaleString(MSG_RATEPANEL_PAY_PER_UNIT_GAD),Locale->loc_MonSmallCS);
  173.     else
  174.         SPrintf(Buffer,LocaleString(MSG_RATEPANEL_PAY_PER_UNIT_GAD),"Pay");
  175.  
  176.     return(Buffer);
  177. }
  178.  
  179.     /* InsertGrouping(STRPTR Buffer,STRPTR GroupData,STRPTR GroupSeparator):
  180.      *
  181.      *    Tricky stuff, folks! This beauty will insert grouping characters
  182.      *    into a readily-prepared string buffer filled with numeric
  183.      *    contents. It takes the group separator tokens and group separator
  184.      *    strings into account.
  185.      */
  186.  
  187. VOID
  188. InsertGrouping(STRPTR Buffer,STRPTR GroupData,STRPTR GroupSeparator)
  189. {
  190.     UBYTE    LocalBuffer[80];    // Sufficient, but too large
  191.     STRPTR    Index;
  192.     LONG    i,j,SeparatorSize;
  193.     LONG    Count;                // How many characters per group
  194.     BOOL    RepeatGroupCount;    // Keep repeating group size until end
  195.  
  196.         // Set up for the first group
  197.  
  198.     switch(*GroupData)
  199.     {
  200.         case 0:            // Repeat current grouping scheme until end
  201.         case 255:        // No further grouping is to be performed
  202.  
  203.             Count = 0;
  204.  
  205.             break;
  206.  
  207.         default:        // Initial group size
  208.  
  209.             RepeatGroupCount = FALSE;
  210.  
  211.             Count = *GroupData++;
  212.  
  213.             break;
  214.     }
  215.  
  216.         // Check the size of the group separator string
  217.  
  218.     if((SeparatorSize = strlen(GroupSeparator) - 1) < 1)
  219.         Count = 0;
  220.  
  221.         // That where we'll start
  222.  
  223.     Index = LocalBuffer;
  224.  
  225.         // Build the string back to front, we will reverse it later
  226.  
  227.     for(i = strlen(Buffer) - 1, j = 1 ; i >= 0 ; i--, j++)
  228.     {
  229.             // Pick up the next number character
  230.  
  231.         *Index++ = Buffer[i];
  232.  
  233.             // Are we to insert the grouping characters here?
  234.  
  235.         if(Count && j == Count)
  236.         {
  237.             LONG k;
  238.  
  239.                 // Insert the grouping characters
  240.  
  241.             for(k = SeparatorSize ; k >= 0 ; k--)
  242.                 *Index++ = GroupSeparator[k];
  243.  
  244.                 // Reset the group size counter
  245.  
  246.             j = 0;
  247.  
  248.                 // Pick up the next grouping token?
  249.  
  250.             if(!RepeatGroupCount)
  251.             {
  252.                     // Ok, what kind of token is it?
  253.  
  254.                 switch(*GroupData)
  255.                 {
  256.                     case 0:        // Repeat current grouping scheme
  257.  
  258.                         RepeatGroupCount = TRUE;
  259.                         break;
  260.  
  261.                     case 255:    // Perform no further grouping
  262.  
  263.                         Count = 0;
  264.                         break;
  265.  
  266.                     default:    // New group size
  267.  
  268.                         Count = *GroupData++;
  269.                         break;
  270.                 }
  271.             }
  272.         }
  273.     }
  274.  
  275.         // Look how long the resulting string is
  276.  
  277.     j = ((LONG)Index - (LONG)LocalBuffer) - 1;
  278.  
  279.         // Copy it back
  280.  
  281.     Index = Buffer;
  282.  
  283.         // Reverse the order of characters while copying
  284.  
  285.     for(i = j ; i >= 0 ; i--)
  286.         *Index++ = LocalBuffer[i];
  287.  
  288.         // Provide null-termination
  289.  
  290.     *Index = 0;
  291. }
  292.  
  293. VOID
  294. ConvertMonetaryQuantity(LONG Units,STRPTR Destination,BOOL UseCurrency)
  295. {
  296.     UBYTE    IntegerBuffer[80];    // Sufficient, but too large
  297.  
  298.     STRPTR    SignText,            // Signed/unsigned quantity text
  299.             SpaceText,            // Currency/number separation
  300.             Currency;            // The name of the currency
  301.     LONG    SpaceSep,            // A space separates currency and quantity?
  302.             SignPos,            // Where to place the sign text
  303.             CSPos;                // Where to place the currency text
  304.     LONG    Sign;                // Negative or positive quantity?
  305.  
  306.         // Negative quantity?
  307.  
  308.     if(Units < 0)
  309.     {
  310.         Sign = -1;
  311.  
  312.         Units = -Units;
  313.     }
  314.     else
  315.         Sign = 1;
  316.  
  317.         // Does this currency sport a fractional smaller currency?
  318.  
  319.     if(Locale->loc_MonFracDigits)
  320.     {
  321.         UBYTE    NumberBuffer[5],
  322.                 FractionBuffer[40];
  323.         LONG    Integer,
  324.                 Fraction,
  325.                 Scale;
  326.         LONG    i;
  327.  
  328.             // Prepare the formatting string
  329.  
  330.         SPrintf(NumberBuffer,"%%0%ldld",Locale->loc_MonFracDigits);
  331.  
  332.             // Turn the number of fractional digits into a power of ten
  333.  
  334.         for(i = 0, Scale = 1 ; i < Locale->loc_MonFracDigits ; i++)
  335.             Scale *= 10;
  336.  
  337.             // Split the quantity in integer and fractional part
  338.  
  339.         Integer        = Units / Scale;
  340.         Fraction    = Units % Scale;
  341.  
  342.             // Build the integer text
  343.  
  344.         SPrintf(IntegerBuffer,"%ld",Integer);
  345.  
  346.         InsertGrouping(IntegerBuffer,Locale->loc_MonGrouping,Locale->loc_MonGroupSeparator);
  347.  
  348.             // Build the fractional text
  349.  
  350.         SPrintf(FractionBuffer,NumberBuffer,Fraction);
  351.  
  352.         InsertGrouping(FractionBuffer,Locale->loc_MonFracGrouping,Locale->loc_MonFracGroupSeparator);
  353.  
  354.             // Add the monetary decimal point
  355.  
  356.         strcat(IntegerBuffer,Locale->loc_MonDecimalPoint);
  357.  
  358.             // Add the fractional part
  359.  
  360.         strcat(IntegerBuffer,FractionBuffer);
  361.     }
  362.     else
  363.     {
  364.             // Build the integer text
  365.  
  366.         SPrintf(IntegerBuffer,"%ld",Units);
  367.  
  368.         InsertGrouping(IntegerBuffer,Locale->loc_MonGrouping,Locale->loc_MonGroupSeparator);
  369.     }
  370.  
  371.         // Pick up the appropriate formatting parameters
  372.  
  373.     if(Sign < 0)
  374.     {
  375.         SignText    = Locale->loc_MonNegativeSign;
  376.         SpaceSep    = Locale->loc_MonNegativeSpaceSep;
  377.         SignPos        = Locale->loc_MonNegativeSignPos;
  378.         CSPos        = Locale->loc_MonNegativeCSPos;
  379.     }
  380.     else
  381.     {
  382.         SignText    = Locale->loc_MonPositiveSign;
  383.         SpaceSep    = Locale->loc_MonPositiveSpaceSep;
  384.         SignPos        = Locale->loc_MonPositiveSignPos;
  385.         CSPos        = Locale->loc_MonPositiveCSPos;
  386.     }
  387.  
  388.         // Are we to use the currency symbol?
  389.  
  390.     if(UseCurrency)
  391.     {
  392.             // Pick up the currency text
  393.  
  394.         Currency = Locale->loc_MonCS;
  395.  
  396.             // Take care of the separation information
  397.  
  398.         if(SpaceSep == SS_NOSPACE)
  399.             SpaceText = "";
  400.         else
  401.             SpaceText = " ";
  402.     }
  403.     else
  404.         Currency = SpaceText = "";
  405.  
  406.         // Now merge all the information into one single string
  407.  
  408.     if(CSPos == CSP_PRECEDES)
  409.     {
  410.         switch(SignPos)
  411.         {
  412.             case SP_PARENS:
  413.  
  414.                 // (Currency <Space> Sign Value)
  415.                 SPrintf(Destination,"(%s%s%s%s)",Currency,SpaceText,SignText,IntegerBuffer);
  416.                 break;
  417.  
  418.             case SP_PREC_ALL:
  419.  
  420.                 // Sign Currency <Space> Value
  421.                 SPrintf(Destination,"%s%s%s%s",SignText,Currency,SpaceText,IntegerBuffer);
  422.                 break;
  423.  
  424.             case SP_SUCC_ALL:
  425.  
  426.                 // Currency <Space> Value Sign
  427.                 SPrintf(Destination,"%s%s%s%s",Currency,SpaceText,IntegerBuffer,SignText);
  428.                 break;
  429.  
  430.             case SP_PREC_CURR:
  431.  
  432.                 // Sign Currency <Space> Value
  433.                 SPrintf(Destination,"%s%s%s%s",SignText,Currency,SpaceText,IntegerBuffer);
  434.                 break;
  435.  
  436.             case SP_SUCC_CURR:
  437.  
  438.                 // Currency Sign <Space> Value
  439.                 SPrintf(Destination,"%s%s%s%s",Currency,SignText,SpaceText,IntegerBuffer);
  440.                 break;
  441.         }
  442.     }
  443.     else
  444.     {
  445.         switch(SignPos)
  446.         {
  447.             case SP_PARENS:
  448.  
  449.                 // (Sign Value <Space> Currency)
  450.                 SPrintf(Destination,"(%s%s%s%s)",SignText,IntegerBuffer,SpaceText,Currency);
  451.                 break;
  452.  
  453.             case SP_PREC_ALL:
  454.  
  455.                 // Sign Value <Space> Currency
  456.                 SPrintf(Destination,"%s%s%s%s",SignText,IntegerBuffer,SpaceText,Currency);
  457.                 break;
  458.  
  459.             case SP_SUCC_ALL:
  460.  
  461.                 // Value <Space> Currency Sign
  462.                 SPrintf(Destination,"%s%s%s%s",IntegerBuffer,SpaceText,Currency,SignText);
  463.                 break;
  464.  
  465.             case SP_PREC_CURR:
  466.  
  467.                 // Value <Space> Sign Currency
  468.                 SPrintf(Destination,"%s%s%s%s",IntegerBuffer,SpaceText,SignText,Currency);
  469.                 break;
  470.  
  471.             case SP_SUCC_CURR:
  472.  
  473.                 // Value <Space> Currency Sign
  474.                 SPrintf(Destination,"%s%s%s%s",IntegerBuffer,SpaceText,Currency,SignText);
  475.                 break;
  476.         }
  477.     }
  478. }
  479.  
  480.     /* CreateSum(LONG Quantity):
  481.      *
  482.      *    Create a string containing a monetary quantity formatted
  483.      *    according to the current locale rules.
  484.      */
  485.  
  486. STRPTR
  487. CreateSum(LONG Quantity,BOOL UseCurrency)
  488. {
  489.     STATIC UBYTE Buffer[100];
  490.  
  491.     if(Locale)
  492.         ConvertMonetaryQuantity(Quantity,Buffer,UseCurrency);
  493.     else
  494.         SPrintf(Buffer,"%ld.%02ld",Quantity / 100,Quantity % 100);
  495.  
  496.     return(Buffer);
  497. }
  498.  
  499.     /* LocalizeString(STRPTR *Strings,LONG From,LONG To):
  500.      *
  501.      *    Localize an array of strings.
  502.      */
  503.  
  504. VOID
  505. LocalizeString(STRPTR *Strings,LONG From,LONG To)
  506. {
  507.     if(!Strings[0])
  508.     {
  509.         LONG i,j;
  510.  
  511.         for(i = From, j = 0 ; i <= To ; i++, j++)
  512.             Strings[j] = LocaleString(i);
  513.     }
  514. }
  515.  
  516.     /* LocalizeStringTable(STRPTR *Strings,LONG *Table)
  517.      *
  518.      *    Localize an array of strings by table.
  519.      */
  520.  
  521. VOID
  522. LocalizeStringTable(STRPTR *Strings,LONG *Table)
  523. {
  524.     while(*Table != -1)
  525.         *Strings++ = LocaleString(*Table++);
  526.  
  527.     *Strings = NULL;
  528. }
  529.  
  530. VOID
  531. LocalizeMenuTable(struct NewMenu *Menu,LONG *Table)
  532. {
  533.     STRPTR    Label,Shortcut;
  534.     LONG    From = 0;
  535.  
  536.     while(Menu->nm_Type != NM_END)
  537.     {
  538.         Shortcut = LocaleString(Table[From]);
  539.  
  540.         if(Shortcut[0] && !Shortcut[1])
  541.             Label = Shortcut + 2;
  542.         else
  543.         {
  544.             Label        = Shortcut;
  545.             Shortcut    = NULL;
  546.         }
  547.  
  548.         switch(Menu->nm_Type)
  549.         {
  550.             case NM_TITLE:
  551.  
  552.                 Menu->nm_Label = Label;
  553.  
  554.                 From++;
  555.  
  556.                 break;
  557.  
  558.             case NM_ITEM:
  559.             case NM_SUB:
  560.  
  561.                 if(Menu->nm_Label != NM_BARLABEL)
  562.                 {
  563.                     Menu->nm_Label        = Label;
  564.                     Menu->nm_CommKey    = Shortcut;
  565.  
  566.                     From++;
  567.                 }
  568.  
  569.                 break;
  570.         }
  571.  
  572.         Menu++;
  573.     }
  574. }
  575.  
  576.     /* LocaleString(ULONG ID):
  577.      *
  578.      *    Obtain a string from the translation pool.
  579.      */
  580.  
  581. STRPTR
  582. LocaleString(ULONG ID)
  583. {
  584.     extern struct CatCompArrayType    *AppStrings;
  585.     extern WORD                         NumAppStrings;
  586.  
  587.     STRPTR Builtin;
  588.  
  589.     if(ID < NumAppStrings && AppStrings[ID].cca_ID == ID)
  590.         Builtin = AppStrings[ID].cca_Str;
  591.     else
  592.     {
  593.         LONG Left,Mid,Right;
  594.  
  595.             // Binary search, note: can be applied here
  596.             // only because the catalog entries are
  597.             // stored in ascending ID order. But actually,
  598.             // this piece of code should never get called.
  599.  
  600.         Left    = 0;
  601.         Right    = NumAppStrings - 1;
  602.  
  603.         do
  604.         {
  605.             Mid = (Left + Right) / 2;
  606.  
  607.             if(ID < AppStrings[Mid].cca_ID)
  608.                 Right    = Mid - 1;
  609.             else
  610.                 Left    = Mid + 1;
  611.         }
  612.         while(ID != AppStrings[Mid].cca_ID && Left <= Right);
  613.  
  614.         if(ID == AppStrings[Mid].cca_ID)
  615.             Builtin = AppStrings[Mid].cca_Str;
  616.         else
  617.             Builtin = "";
  618.     }
  619.  
  620.     if(Catalog)
  621.     {
  622.         STRPTR String = GetCatalogStr(Catalog,ID,Builtin);
  623.  
  624.         if(String[0])
  625.             return(String);
  626.     }
  627.  
  628.     return(Builtin);
  629. }
  630.  
  631. STRPTR __saveds __asm
  632. LocaleHookFunc(REG(a0) struct Hook *Hook,REG(a1) LONG ID)
  633. {
  634.     return(LocaleString(ID));
  635. }
  636.  
  637. STATIC LONG __saveds __asm
  638. FormatDateHookFunc(REG(a0) struct Hook *Hook,REG(a1) UBYTE Char)
  639. {
  640.     STRPTR String = Hook->h_Data;
  641.  
  642.     *String++ = Char;
  643.  
  644.     Hook->h_Data = String;
  645.  
  646.     return(TRUE);
  647. }
  648.  
  649.     /* FormatStamp():
  650.      *
  651.      *    Convert a date stamp into human readable
  652.      *    form by taking the current locale parameters
  653.      *    into account.
  654.      */
  655.  
  656. BOOL
  657. FormatStamp(struct DateStamp *Stamp,STRPTR DateBuffer,STRPTR TimeBuffer,STRPTR BothBuffer,BOOL SubstituteDay)
  658. {
  659.     struct DateStamp Now;
  660.  
  661.         // If no time stamp given, do with current time
  662.  
  663.     if(!Stamp)
  664.         DateStamp(Stamp = &Now);
  665.  
  666.         // Is the current locale available?
  667.  
  668.     if(Locale)
  669.     {
  670.         struct Hook LocalHook = {{NULL}, (HOOKFUNC)FormatDateHookFunc};
  671.  
  672.             // Combine date and time text?
  673.  
  674.         if(BothBuffer && !SubstituteDay)
  675.         {
  676.             LocalHook.h_Data = BothBuffer;
  677.  
  678.             FormatDate(Locale,Locale->loc_DateTimeFormat,Stamp,&LocalHook);
  679.  
  680.             StripSpaces(BothBuffer);
  681.         }
  682.         else
  683.         {
  684.             UBYTE    LocalDateBuffer[40],
  685.                     LocalTimeBuffer[40];
  686.  
  687.                 // Provide storage space
  688.  
  689.             if(BothBuffer)
  690.             {
  691.                 DateBuffer = LocalDateBuffer;
  692.                 TimeBuffer = LocalTimeBuffer;
  693.             }
  694.  
  695.                 // Do we have a date buffer to fill?
  696.  
  697.             if(DateBuffer)
  698.             {
  699.                     // Are we to substitute the current day with
  700.                     // text such as today, yesterday, etc.?
  701.  
  702.                 if(SubstituteDay)
  703.                 {
  704.                     struct DateStamp    Today;
  705.                     STRPTR                String;
  706.  
  707.                         // Get the current time
  708.  
  709.                     DateStamp(&Today);
  710.  
  711.                         // Does the date refer to yesterday?
  712.  
  713.                     if(Stamp->ds_Days == Today.ds_Days - 1)
  714.                         String = GetLocaleStr(Locale,YESTERDAYSTR);
  715.                     else
  716.                     {
  717.                             // Does the date refer to today?
  718.  
  719.                         if(Stamp->ds_Days == Today.ds_Days)
  720.                             String = GetLocaleStr(Locale,TODAYSTR);
  721.                         else
  722.                         {
  723.                                 // Does the date refer to tomorrow?
  724.  
  725.                             if(Stamp->ds_Days == Today.ds_Days + 1)
  726.                                 String = GetLocaleStr(Locale,TOMORROWSTR);
  727.                             else
  728.                             {
  729.                                 String            = NULL;
  730.                                 SubstituteDay    = NULL;
  731.                             }
  732.                         }
  733.                     }
  734.  
  735.                     if(String)
  736.                         strcpy(DateBuffer,String);
  737.                     else
  738.                         DateBuffer[0] = 0;
  739.                 }
  740.  
  741.                 if(!SubstituteDay)
  742.                 {
  743.                     LocalHook.h_Data = DateBuffer;
  744.  
  745.                     FormatDate(Locale,Locale->loc_DateFormat,Stamp,&LocalHook);
  746.                 }
  747.  
  748.                 StripSpaces(DateBuffer);
  749.             }
  750.  
  751.             if(TimeBuffer)
  752.             {
  753.                 LocalHook.h_Data = TimeBuffer;
  754.  
  755.                 FormatDate(Locale,Locale->loc_TimeFormat,Stamp,&LocalHook);
  756.  
  757.                 StripSpaces(TimeBuffer);
  758.             }
  759.  
  760.                 // Combine date and time
  761.  
  762.             if(BothBuffer)
  763.             {
  764.                 strcpy(BothBuffer,DateBuffer);
  765.                 strcat(BothBuffer," ");
  766.                 strcat(BothBuffer,TimeBuffer);
  767.             }
  768.         }
  769.     }
  770.     else
  771.     {
  772.         struct DateTime    DateTime;
  773.         UBYTE            LocalDateBuffer[40],
  774.                         LocalTimeBuffer[40];
  775.  
  776.             // Provide storage space
  777.  
  778.         if(BothBuffer)
  779.         {
  780.             DateBuffer = LocalDateBuffer;
  781.             TimeBuffer = LocalTimeBuffer;
  782.         }
  783.  
  784.             // No locale, so we will use dos.library instead.
  785.  
  786.         CopyMem(Stamp,&DateTime.dat_Stamp,sizeof(struct DateStamp));
  787.  
  788.         DateTime.dat_Format        = FORMAT_DOS;
  789.         DateTime.dat_Flags        = SubstituteDay ? DTF_SUBST : NULL;
  790.         DateTime.dat_StrDay        = NULL;
  791.         DateTime.dat_StrDate    = DateBuffer;
  792.         DateTime.dat_StrTime    = TimeBuffer;
  793.  
  794.         if(!DateToStr(&DateTime))
  795.             return(FALSE);
  796.  
  797.         if(DateBuffer)
  798.             StripSpaces(DateBuffer);
  799.  
  800.         if(TimeBuffer)
  801.             StripSpaces(TimeBuffer);
  802.  
  803.             // Combine date and time
  804.  
  805.         if(BothBuffer)
  806.         {
  807.             strcpy(BothBuffer,DateBuffer);
  808.             strcat(BothBuffer," ");
  809.             strcat(BothBuffer,TimeBuffer);
  810.         }
  811.     }
  812.  
  813.     return(TRUE);
  814. }
  815.  
  816.     /* FormatTime(STRPTR Buffer,LONG Hours,LONG Minutes,LONG Seconds):
  817.      *
  818.      *    Given hours, minutes and seconds, format this data into
  819.      *    a human-readable string.
  820.      */
  821.  
  822. VOID
  823. FormatTime(STRPTR Buffer,LONG Hours,LONG Minutes,LONG Seconds)
  824. {
  825.     if(Locale)
  826.     {
  827.         struct Hook LocalHook = {{NULL}, (HOOKFUNC)FormatDateHookFunc};
  828.  
  829.         struct DateStamp Stamp;
  830.  
  831.         Stamp.ds_Days        = 0;
  832.         Stamp.ds_Minute        = Hours * 60 + Minutes;
  833.         Stamp.ds_Tick        = MAX(0,Seconds) * TICKS_PER_SECOND;
  834.  
  835.         LocalHook.h_Data = Buffer;
  836.  
  837.         if(Seconds < 0)
  838.             FormatDate(Locale,Locale->loc_ShortTimeFormat,&Stamp,&LocalHook);
  839.         else
  840.             FormatDate(Locale,Locale->loc_TimeFormat,&Stamp,&LocalHook);
  841.     }
  842.     else
  843.     {
  844.         if(Seconds < 0)
  845.             SPrintf(Buffer,"%02ld:%02ld",Hours,Minutes);
  846.         else
  847.             SPrintf(Buffer,"%02ld:%02ld:%02ld",Hours,Minutes,Seconds);
  848.     }
  849. }
  850.  
  851.     /* StandardShowTime(struct Gadget *SomeGadget,LONG Level):
  852.      *
  853.      *    Callback routine to display some time level.
  854.      */
  855.  
  856. STRPTR __saveds __stdargs
  857. StandardShowTime(struct Gadget *SomeGadget,LONG Level)
  858. {
  859.     return(LocaleSeconds(Level));
  860. }
  861.